package com.zzyl.nursing.service.impl;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.huaweicloud.sdk.core.utils.JsonUtils;
import com.huaweicloud.sdk.iotda.v5.IoTDAClient;
import com.huaweicloud.sdk.iotda.v5.model.*;
import com.zzyl.common.constant.CacheConstants;
import com.zzyl.common.core.domain.AjaxResult;
import com.zzyl.common.exception.base.BaseException;
import com.zzyl.common.utils.StringUtils;
import com.zzyl.common.utils.uuid.UUID;
import com.zzyl.nursing.dto.DeviceDto;
import com.zzyl.nursing.vo.DeviceDetailVo;
import com.zzyl.nursing.vo.ProductVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.zzyl.nursing.mapper.DeviceMapper;
import com.zzyl.nursing.domain.Device;
import com.zzyl.nursing.service.IDeviceService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.transaction.annotation.Transactional;

/**
 * 设备Service业务层处理
 * 
 * @author jingchengjiang
 * @date 2025-09-22
 */
@Service
public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> implements IDeviceService
{
    @Autowired
    private DeviceMapper deviceMapper;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private IoTDAClient client;
    /**
     * 查询设备
     * 
     * @param id 设备主键
     * @return 设备
     */
    @Override
    public Device selectDeviceById(Long id)
    {
        return deviceMapper.selectById(id);
    }

    /**
     * 查询设备列表
     * 
     * @param device 设备
     * @return 设备
     */
    @Override
    public List<Device> selectDeviceList(Device device)
    {
        return deviceMapper.selectDeviceList(device);
    }

    /**
     * 新增设备
     * 
     * @param device 设备
     * @return 结果
     */
    @Override
    public int insertDevice(Device device)
    {
        return deviceMapper.insert(device);
    }

    /**
     * 修改设备
     * 
     * @param dto 设备
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateDevice(DeviceDto dto)
    {
        //查询设备是否存在
        Device dbDevice = getById(dto.getId());
        if(ObjectUtil.isEmpty(dbDevice)){
            throw new BaseException("设备不存在");
        }

        //先更新设备
        //如果是随身设备，物理位置设为-1
        if (dto.getLocationType().equals(0)) {
            dto.setPhysicalLocationType(-1);
        }
        //更新数据库中设备信息
        try {
            Device bean = BeanUtil.toBean(dto, Device.class);
            deviceMapper.updateDevice(bean);
        } catch (Exception e) {
            throw new BaseException("该老人/位置已绑定该产品，请重新选择");
        }
        //更新华为云设备信息
        UpdateDeviceRequest request = new UpdateDeviceRequest();
        request.setDeviceId(dto.getIotId());

        UpdateDevice body = new UpdateDevice();
        body.setDeviceName(dto.getDeviceName());

        request.setBody(body);
        client.updateDevice(request);
        /*
        UpdateProductRequest request = new UpdateProductRequest();
        UpdateProduct body = new UpdateProduct();
        request.withBody(body);
        try {
            UpdateProductResponse response = client.updateProduct(request);
         */
        return 1;
    }

    /**
     * 批量删除设备
     * 
     * @param ids 需要删除的设备主键
     * @return 结果
     */
    @Override
    public int deleteDeviceByIds(Long[] ids)
    {
        return deviceMapper.deleteBatchIds(Arrays.asList(ids));
    }

    /**
     * 删除设备信息
     * 
     * @param id 设备主键
     * @return 结果
     */
    @Override
    public int deleteDeviceById(Long id)
    {
        return deviceMapper.deleteById(id);
    }

    @Override
    public void syncProductList() {
        //从华为云查询产品信息
        ListProductsRequest request = new ListProductsRequest();
        //设置条数
        request.setLimit(50);
        //发起请求
        ListProductsResponse response = client.listProducts(request);
        List<ProductSummary> products = response.getProducts();
        //存储信息到Redis中
        redisTemplate.opsForValue().set(CacheConstants.ALL_PRODUCTS_LIST_KEY, JSONUtil.toJsonStr(products));
    }

    @Override
    public List<ProductVo> allProduct() {
        //从redis中查询数据
        String JsonStr = redisTemplate.opsForValue().get(CacheConstants.ALL_PRODUCTS_LIST_KEY);
        //如果数据为空，则返回一个空集合
        if (StrUtil.isBlank(JsonStr)){
            return null;
//            return Collections.emptyList();
        }
        //解析数据，并返回
        return JSONUtil.toList(JsonStr, ProductVo.class);
    }

    /**
     * 注册设备
     * @param dto
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void registerDevice(DeviceDto dto) {
        //判断设备名称是否重复
        Long count1 = lambdaQuery().eq(Device::getDeviceName, dto.getDeviceName()).count();
        //检验设备标识码是否重复
        if (count1 != null && count1 > 0){
            throw new BaseException("设备名称重复");
        }
        //判断设备标识码是否重复
        Long count2 = lambdaQuery()
                .eq(Device::getNodeId, dto.getNodeId())
                .count();
        if(count2 != null && count2 > 0){
            throw new BaseException("标识错误");
        }
        //校验同一位置是否绑定相同产品
        Long count3 = lambdaQuery()
                .eq(Device::getBindingLocation, dto.getBindingLocation())
                .eq(Device::getLocationType, dto.getLocationType())
                .eq(Device::getPhysicalLocationType, dto.getPhysicalLocationType())
                .eq(Device::getProductKey, dto.getProductKey())
                .count();
        if(count3 != null && count3 > 0){
            throw new BaseException("同一位置只能绑定一个产品");
        }
        //先保存到华为云
        AddDeviceRequest request = new AddDeviceRequest();

        AddDevice addDevice = new AddDevice();
        addDevice.setNodeId(dto.getNodeId());
        addDevice.setDeviceName(dto.getDeviceName());
        addDevice.setProductId(dto.getProductKey());

        AuthInfo authInfo = new AuthInfo();
        String secret = IdUtil.fastSimpleUUID();
        authInfo.setSecret(secret);
        addDevice.setAuthInfo(authInfo);
        request.setBody(addDevice);

        AddDeviceResponse response = null;
        try {
            response = client.addDevice((request));
            if (response == null){
                throw new RuntimeException("调用华为云返回null");
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        //缺了三个字段,补齐后保存到数据库
        String deviceId = response.getDeviceId();
        Device device = BeanUtil.toBean(dto, Device.class);
        device.setSecret(secret);
        device.setIotId(deviceId);
        device.setHaveEntranceGuard(0);
        this.save(device);
    }

    @Override
    public DeviceDetailVo queryDeviceDetail(String iotId) {
        //先查数据库
        Device device = lambdaQuery()
                .eq(Device::getIotId, iotId)
                .one();
        if(device == null){
            throw new BaseException("设备不存在");
        }
        //再查询华为云,补充两个字段 deviceStatus,activeTime
        //创建请求
        ShowDeviceRequest request = new ShowDeviceRequest();
        //设备ID
        request.withDeviceId(iotId);
        //调用
        ShowDeviceResponse response = client.showDevice(request);

        String status = response.getStatus();
        String activeTime = response.getActiveTime();
        //转换
        DeviceDetailVo vo = BeanUtil.toBean(device, DeviceDetailVo.class);
        //设置设备状态
        vo.setDeviceStatus(status);

        if(activeTime!=null){
            // 定义解析格式
            DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE_TIME;

            // 1. 解析为UTC时区的ZonedDateTime
            ZonedDateTime utcDateTime = ZonedDateTime.parse(activeTime, formatter);

            // 2. 转换为东八区(Asia/Shanghai)的时间
            ZonedDateTime shanghaiDateTime = utcDateTime.withZoneSameInstant(ZoneId.of("Asia/Shanghai"));

            // 3. 提取为LocalDateTime
            LocalDateTime localDateTime = shanghaiDateTime.toLocalDateTime();
            vo.setActiveTime(localDateTime);
        }

        return vo;
    }

    @Override
    public AjaxResult queryServiceProperties(String iotId) {

        //调用华为云的影子接口
        ShowDeviceShadowRequest request = new ShowDeviceShadowRequest();
        request.withDeviceId(iotId);
        ShowDeviceShadowResponse response = client.showDeviceShadow(request);
        System.out.println("response = " + JSONUtil.toJsonStr(response));
        String eventTime = response.getShadow().get(0).getReported().getEventTime();

        // 定义输入时间格式（UTC不带时区信息，但末尾的Z表示UTC）
        DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss'Z'");

        // 解析为UTC时区的时间
        ZonedDateTime utcTime = ZonedDateTime.parse(eventTime, inputFormatter.withZone(java.time.ZoneOffset.UTC));

        // 转换为东八区（Asia/Shanghai）时间
        ZonedDateTime cstTime = utcTime.withZoneSameInstant(java.time.ZoneId.of("Asia/Shanghai"));

        // 定义输出格式
        DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        // 格式化输出
        String result = cstTime.format(outputFormatter);
        //因为运行时本质上这个object是LinkedHashMap类型，所以才能强转，通过debug看到的
        LinkedHashMap<String,Object> properties = (LinkedHashMap<String, Object>) response.getShadow().get(0).getReported().getProperties();
        List<Map<String,Object>> list = new ArrayList<>();
        //遍历：foreach、迭代器iterator、keySet
        properties.forEach((k,v)->{
            Map<String,Object> map = new HashMap<>();
            list.add(map);
            map.put("functionId",k);
            map.put("value",v);
            map.put("eventTime",result);
        });
        return AjaxResult.success(list);
    }

    @Override
    public int deleteDeviceByIotId(String iotId) {
        
        DeleteDeviceRequest request = new DeleteDeviceRequest();
        
        request.setDeviceId(iotId);
        
        remove(new LambdaQueryWrapper<Device>().eq(Device::getIotId,iotId));
        
        client.deleteDevice(request);
        return 1;
        
    }


}
